/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.ui.util;

import java.awt.Container;
import java.awt.Frame;
import java.io.File;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import org.apache.log4j.Logger;

import who.tmap.bo.Attrs;
import who.tmap.bo.impl.BizObjectFactory;
import who.tmap.common.TMapException;
import who.tmap.dao.DataDAO;
import who.tmap.dao.TMapDAOException;
import who.tmap.dao.impl.DAOFactory;
import who.tmap.imp.CSVImportAdapter;
import who.tmap.imp.ExcelImportAdapter;
import who.tmap.imp.ImportAdapter;
import who.tmap.imp.ODBCDSNLessImportAdapter;
import who.tmap.toolkit.impl.PolygonNamesToAttrsHelper;
import who.tmap.toolkit.shape.MapShape;
import who.tmap.ui.dataimportwiz.JDialogDataImportWizard;

/**
 * @author stl
 *
 */
public class DataUIHelper extends BaseUIHelper {

    private static Logger logger = Logger.getLogger(DataUIHelper.class);
     
    public static Object[] AttrTypesUI = {"BigDecimal", "Boolean", "Byte", "Short", "Integer", "Long", "Float", "Double", "String"};
    public static String DEFAULT_ATTR_TYPE_UI ="String";
    public static String DEFAULT_DATA_ATTR_TYPE_UI ="Double"; 
    public static String DEFAULT_DATA_ATTR_TYPE =Double.class.getName();     
    
    public static String[] AttrTypes = { BigDecimal.class.getName(), Boolean.class.getName(), Byte.class.getName(), 
    									 Short.class.getName(), Integer.class.getName(), Long.class.getName(), 
    									 Float.class.getName(), Double.class.getName(), String.class.getName() };
    
    public String getAttrTypeForUIString( String uiString ) {
    	String str ="";
    	
    	for( int ct =0; ct < AttrTypesUI.length; ct++ ) {
    		if ( ((String)AttrTypesUI[ ct ]).equals( uiString ) ) {
    			str =(String)AttrTypes[ ct ];
    			break;
    		}
    	}
    	
    	return str;
    }
    
    public String getUIStringForAttrType( String attrType ) {
    	String str ="";
    	
    	for( int ct =0; ct < AttrTypesUI.length; ct++ ) {
    		if ( ((String)AttrTypes[ ct ]).equals( attrType ) ) {
    			str =(String)AttrTypesUI[ ct ];
    			break;
    		}
    	}
    	
    	return str;
    }    
    
	public void saveAttributes( Container container, File file, Attrs attrs ) {
        try {
            DataDAO attrsDAO =(DataDAO)DAOFactory.getInstance().get( DAOFactory.ATTRS );
            if ( file.getAbsolutePath().toUpperCase().endsWith( FileChooserFilter.DATA_EXT.toUpperCase() ) ) {
            	attrsDAO.save( file.getAbsolutePath(), attrs );
            } else if ( file.getAbsolutePath().toUpperCase().endsWith( FileChooserFilter.EXCEL_EXT.toUpperCase() ) ) {
            	attrsDAO.saveToExcel( file.getAbsolutePath(), attrs );            	
            } else if ( file.getAbsolutePath().toUpperCase().endsWith( FileChooserFilter.CSV_EXT.toUpperCase() ) ) {
            	attrsDAO.saveToCSV( file.getAbsolutePath(), attrs );            	
            } else if ( file.getAbsolutePath().toUpperCase().endsWith( FileChooserFilter.DBF_EXT.toUpperCase() ) ) {
            	attrsDAO.saveToDBF( file.getAbsolutePath(), attrs );            	
            }
        } catch (TMapDAOException e) {
            miscUIHelper.displayErrorMessage( container, e );
        }	    
	}
	
	public File saveAttributesAs( Container container, Attrs attrs ) {
	    File file =null;
		JFileChooser fileChooser = new JFileChooser();

		FileFilter defaultFilter =new FileChooserFilter( FileChooserFilter.DATA_EXT );
		fileChooser.addChoosableFileFilter( defaultFilter );	
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.DBF_EXT ) );
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.EXCEL_EXT ) );			
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.CSV_EXT ) );	
	
		fileChooser.setCurrentDirectory( getDataDir( container ) );
		fileChooser.setSelectedFile( new File( "*" + FileChooserFilter.DATA_EXT ));
		
		fileChooser.setFileFilter( defaultFilter );
		
		// Save file dialog.
		int retVal =fileChooser.showSaveDialog(container);
		
		if ( retVal == JFileChooser.APPROVE_OPTION ) {
			file =fileChooser.getSelectedFile();
		    logger.debug( "selectedFile=[" + file + "]" );
		    
		    setDataDir( file.getParentFile() );

	        if ( file.exists() ) {

	            int n =JOptionPane.showConfirmDialog( container,
	                    "This file already exists. Do you want to erase it?",
	                    "Save Attributes",
	                    JOptionPane.YES_NO_OPTION);
	            if ( n == JOptionPane.NO_OPTION ) {
	                file =null;
	            }
	        }
	        
	        if ( file != null ) {
	        	
	        	// add extension if necessary
	        	if ( !file.getAbsolutePath().toLowerCase().endsWith( FileChooserFilter.DATA_EXT ) 
	        		&& !file.getAbsolutePath().toLowerCase().endsWith( FileChooserFilter.CSV_EXT )
	        		&& !file.getAbsolutePath().toLowerCase().endsWith( FileChooserFilter.DBF_EXT )	
	        		&& !file.getAbsolutePath().toLowerCase().endsWith( FileChooserFilter.EXCEL_EXT )		        		
	        		&& file.getName().indexOf(".") == -1 ) {
	        		file =new File( file.getAbsolutePath() + "." + ((FileChooserFilter)fileChooser.getFileFilter()).getExtension() );
	        	}
	        	
	            saveAttributes( container, file, attrs );
	        }

		}
		
		return file;
	}	    
	
	public boolean openAttributes( Container container, DataTableDataModel dataModel ) throws Exception  {
		boolean changed =false;
		JFileChooser fileChooser = new JFileChooser();
		FileFilter defaultFileFilter = new FileChooserFilter( FileChooserFilter.DATA_EXT );
		fileChooser.addChoosableFileFilter( defaultFileFilter );
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.SHAPE_DBF_FILE_EXT ) );
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.EXCEL_EXT ) );
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.CSV_EXT ) );
		fileChooser.addChoosableFileFilter( new FileChooserFilter( FileChooserFilter.MDB_EXT ) );
		fileChooser.setFileFilter( defaultFileFilter );
		
		fileChooser.setCurrentDirectory( getDataDir( container ) );
		
		// Open file dialog.
		int retVal =fileChooser.showOpenDialog(	container );
		
		if ( retVal == JFileChooser.APPROVE_OPTION ) {		
		
			File file =fileChooser.getSelectedFile();
			setDataDir( file.getParentFile() );
		    	    
			changed =loadAttributes( container, dataModel, file );
		}
	    
	    return changed;
	}   
	
	public Attrs reloadFromDataSource( Container container, Map<String, String> dsProperties, boolean useUI ) throws Exception {
		DataDAO attrsDAO =(DataDAO)DAOFactory.getInstance().get( DAOFactory.ATTRS );
		Attrs attrs =null;
			
		String dsType =dsProperties.get( ImportAdapter.DS_TYPE );
		
		if ( ( dsType.equals( FileChooserFilter.DATA_EXT ) ) 
			|| ( dsType.equals( FileChooserFilter.DBF_EXT ) ) ) {
			
			String fileName =dsProperties.get( ImportAdapter.FILE_NAME );
			String confirmedFileName;
			
			if ( useUI ) {
				confirmedFileName =JOptionPane.showInputDialog( null
													, "Please specify the input data file"
													, fileName );
			} else {
				confirmedFileName =fileName;
			}
			
			if ( confirmedFileName != null ) {
				if ( dsType.equals( FileChooserFilter.DATA_EXT ) ) {
					attrs =(Attrs)attrsDAO.load( confirmedFileName );
				} else if ( dsType.equals( FileChooserFilter.DBF_EXT ) ) {
					attrs =(Attrs)attrsDAO.loadDbf( confirmedFileName ); 
				}
				
				dsProperties.put(ImportAdapter.FILE_NAME, confirmedFileName );
			}
		} else {
			String file =dsProperties.get( ImportAdapter.FILE_NAME );
			
			String ext =null;
			if ( dsType.equals( ExcelImportAdapter.class.getName() ) ) {
				ext =FileChooserFilter.EXCEL_EXT;
			} else if ( dsType.equals( CSVImportAdapter.class.getName() ) ) {
				ext =FileChooserFilter.CSV_EXT;
			} else if ( dsType.equals( ODBCDSNLessImportAdapter.class.getName() ) ) {
				ext =FileChooserFilter.MDB_EXT;
			}
			
			attrs =importAttributes( container, ext, new File( file ), dsProperties, useUI );
		}
		
		if ( attrs != null ) {
			attrs.setDsProperties(dsProperties);
		}
		
		return attrs;
	}
	
	public boolean loadAttributes( Container container, DataTableDataModel dataModel, File file ) throws Exception {
		boolean changed =false;
		
	    try {
            DataDAO attrsDAO =(DataDAO)DAOFactory.getInstance().get( DAOFactory.ATTRS );		        
            Attrs attrs =null;

            String fileName =file.getAbsolutePath().toUpperCase();
            
            if ( ( fileName.endsWith( FileChooserFilter.DATA_EXT.toUpperCase() ) )
            		|| ( fileName.endsWith( FileChooserFilter.DBF_EXT.toUpperCase() ) ) ) {
                String ext =null;
                
                if ( fileName.endsWith( FileChooserFilter.DATA_EXT.toUpperCase() ) ) {
                	attrs =(Attrs)attrsDAO.load( file.getAbsolutePath() );
                	ext =FileChooserFilter.DATA_EXT;
                } else {
                	attrs =(Attrs)attrsDAO.loadDbf( file.getAbsolutePath() );
                	ext =FileChooserFilter.DBF_EXT;
                }

                if ( attrs != null ) {
	            	Map<String, String> dsProperties =new TreeMap<String, String>();
	            	
	        		dsProperties.put( ImportAdapter.DS_TYPE, ext );
	        		dsProperties.put( ImportAdapter.FILE_NAME, file.getAbsolutePath() );
	        		
	        		attrs.setDsProperties( dsProperties );
                }
        		
            } else if ( fileName.endsWith( FileChooserFilter.EXCEL_EXT.toUpperCase() ) ) {
            	attrs =importAttributes( container, FileChooserFilter.EXCEL_EXT, file, null, true );
            } else if ( fileName.endsWith( FileChooserFilter.CSV_EXT.toUpperCase() ) ) {
            	attrs =importAttributes( container, FileChooserFilter.CSV_EXT, file, null, true );
            } else if ( fileName.endsWith( FileChooserFilter.MDB_EXT.toUpperCase() ) ) {
            	attrs =importAttributes( container, FileChooserFilter.MDB_EXT, file, null, true );
            }
            
            changed =attrs != null;

            if ( changed ) {
            	dataModel.setAttrs( attrs );
            	
            	if ( fileName.endsWith( FileChooserFilter.MDB_EXT.toUpperCase() ) ) {
            		attrs.getDsProperties().put( ImportAdapter.FILE_NAME, file.getAbsolutePath());
            	}
            }
        } catch (TMapException e1) {
            miscUIHelper.displayErrorMessage( container, e1 );
        }
        
        return changed;
	}
	
	private Attrs importAttributes( Container container, String ext, File file, 
									Map<String, String> dsProperties, boolean useUI ) throws Exception {
    	JDialogDataImportWizard wizard =new JDialogDataImportWizard( 
				javax.swing.JOptionPane.getFrameForComponent( container ), 
				true, 
				ext, 
				file );
    	
    	if ( dsProperties != null ) {
    		wizard.populateDsProperties( dsProperties );
    	}
    	
    	if ( useUI ) {
    		wizard.setVisible( true );
    	}
		
		Attrs attrs =null;
		if ( !wizard.isCancelled() || !useUI ) {
			attrs =wizard.retrieveAttrs();
		}
		
		wizard.dispose();
		
		return attrs;
	}
	
	public void newAttributes( Container container, DataTableDataModel dataModel ) {
	    Attrs attrs =null;
        try {
            attrs = (Attrs)BizObjectFactory.getInstance().get( BizObjectFactory.ATTRS );
        } catch (TMapException e) {
            miscUIHelper.displayErrorMessage( container, e );
        }
        
        dataModel.setAttrs( attrs );
	}
	
	/**
	 * 
	 * @param dataModel
	 * @return true if new data has been imported
	 */
	public boolean importAttributes( DataTableDataModel dataModel, Frame parent ) {
		JDialogDataImportWizard frame = new JDialogDataImportWizard( parent, true, null, null );
		frame.setInvokedByTMapWizard( true );
		frame.setVisible( true);
	
		boolean dataChanged =!frame.isCancelled();
		
		if ( dataChanged ) {
            dataModel.setAttrs( frame.getAttrs() );
		}
		
		frame.dispose();	
		
		return dataChanged;
	}
	
	public boolean usePolygonNameForAttrs( Frame parent, List<MapShape> shapes, StringBuilder polygonColumnName
										 , StringBuilder dataColumnName, DataTableDataModel dataModel ) throws TMapException {
		boolean attrUpdated =false;
		
		if ( dataModel != null && dataModel.getAttrs() != null 
							   && dataModel.getAttrs().getHeader() != null 
							   && dataModel.getAttrs().getHeader().size() > 0 ) {
            int n =JOptionPane.showConfirmDialog( parent,
                    "Do you want to replace your current data with shape file data ?",
                    "Replace current data",
                    JOptionPane.YES_NO_OPTION);
            
            if ( n == JOptionPane.NO_OPTION ) {
                return false;
            }
		}
		
		dataColumnName.setLength( 0 );
		dataColumnName.append( MapUIHelper.DEFAULT_DATA_COLUMN_NAME );
		
		String dataColumnType =Double.class.getName();
		dataModel.setAttrs( 
				new PolygonNamesToAttrsHelper().buildAttrs( shapes
														  , polygonColumnName.toString()
														  , dataColumnName.toString()
														  , dataColumnType ) );
		
		attrUpdated =true;
		
		
		
		return attrUpdated;
	}
	
}
